package uts

import (
	"strings"
)

// ArrConcat 将多个数组的元素全部拼接到一个新数组并返回
func ArrConcat[V any](arr []V, arrs ...[]V) []V {
	for _, a := range arrs {
		arr = append(arr, a...)
	}
	return arr
}

// ArrUnion 将多个数组的元素合并到一个数组，并返回该数组去重后的新数组
func ArrUnion[V comparable](arr []V, arrs ...[]V) []V {
	for _, a := range arrs {
		arr = append(arr, a...)
	}
	return ArrUniq(arr)
}

// ArrChunk 将数组按指定size分组，若不能均分，最后一组包含剩下的元素
func ArrChunk[V any](arr []V, sizes ...int) [][]V {
	var (
		size int
		arr2 [][]V
	)

	if len(sizes) > 0 {
		size = sizes[0]
	}

	for i, l, s := 0, len(arr), max(1, size); i < l; i += s {
		arr2 = append(arr2, arr[i:min(l, i+s)])
	}

	return arr2
}

// ArrIndexOf 按指定条件查找元素，存在时返回下标，否则返回-1
func ArrIndexOf[V comparable, T []V](arr T, val V) int {
	for i, v := range arr {
		if v == val {
			return i
		}
	}
	return -1
}

// ArrIncludes 按指定条件查找元素，存在时返回true，否则返回false
func ArrIncludes[V comparable, T []V](arr T, val V) bool {
	for _, a := range arr {
		if a == val {
			return true
		}
	}
	return false
}

// ArrFill 将数组元素全部填充为指定值
func ArrFill[V any, T []V](arr *T, val V) *T {
	for i := range *arr {
		(*arr)[i] = val
	}
	return arr
}

// ArrFilter 筛选数组元素，剔除不满足fn()==true的元素
func ArrFilter[V any, T []V](arr T, fn func(val V, idx int) bool) T {
	var arr2 T
	for i, a := range arr {
		if fn(a, i) {
			arr2 = append(arr2, a)
		}
	}
	return arr2
}

// ArrMap 重构数组元素，新元素为fn()的返回值
func ArrMap[V any, R any](arr []V, fn func(val V, idx int) R) []R {
	var arr2 []R
	for i, a := range arr {
		arr2 = append(arr2, fn(a, i))
	}
	return arr2
}

// ArrReduce 对数组中的每个元素按序执行fn()，fn会将上次执行结果（prev）作为参数传入，直到最后一次执行并返回结果。
func ArrReduce[V any, R any](arr []V, fn func(prev R, curr V, idx int, arr []V) R, initVal ...R) R {
	var res R

	if len(initVal) > 0 {
		res = initVal[0]
	}

	for i, v := range arr {
		res = fn(res, v, i, arr)
	}

	return res
}

// ArrUniq 数组元素去重
func ArrUniq[V comparable](arr []V) []V {
	var (
		arr2  []V
		cache = make(map[V]bool)
	)

	for _, v := range arr {
		if !cache[v] {
			cache[v] = true
			arr2 = append(arr2, v)
		}
	}

	return arr2
}

// ArrSample 从数组中随机选取指定数量元素
//   - 同一元素不会多次选取，但选取的多个元素可能具有相同值
func ArrSample[V any](arr []V, count ...int) []V {
	var (
		n    int
		arr2 []V
	)

	if len(count) > 0 {
		n = count[0]
	}

	for n = max(1, n); n > 0; n-- {
		switch l := len(arr); l {
		case 0:
			return arr2
		case 1:
			return append(arr2, arr[0])
		default:
			i := RandInt(0, l) + 1
			arr2 = append(arr2, arr[i-1])
			arr = append(arr[:i-1], arr[i:]...)
		}
	}

	return arr2
}

// ArrSampleOne 从数组中随机选取1个元素
func ArrSampleOne[V any](arr []V) V {
	var v V

	if l := len(arr); l > 0 {
		v = arr[RandInt(0, l-1)]
	}

	return v
}

// ArrShuffle 将数组元素打乱顺序
func ArrShuffle[V any](arr []V) []V {
	return ArrSample(arr, len(arr))
}

// ArrCount 返回数组中满足指定条件的元素个数
func ArrCount[V comparable](arr []V, vals ...V) int {
	var (
		val   V
		count int
	)

	if len(vals) > 0 {
		val = vals[0]
	}

	for _, v := range arr {
		if v == val {
			count++
		}
	}

	return count
}

// ArrSum 数组元素求和
func ArrSum[V Numeric](arr []V) V {
	return ArrReduce(arr, func(prev V, curr V, idx int, arr []V) V {
		return prev + curr
	})
}

// ArrMean 数组元素的平均值
func ArrMean[V Numeric](arr []V) float64 {
	var v float64

	if l := len(arr); l > 0 {
		v = float64(ArrSum(arr)) / float64(len(arr))
	}

	return v
}

// ArrProduct 数组元素的乘积
func ArrProduct[V Numeric](arr []V) V {
	return ArrReduce(arr, func(prev V, curr V, idx int, arr []V) V {
		return prev * curr
	}, 1)
}

// ArrFind 查找数组中满足条件的元素，找到时会提前结束，并返回该元素
func ArrFind[V any, T []V](arr T, fn func(val V, idx int) bool) V {
	var empty V
	for i, a := range arr {
		if fn(a, i) {
			return a
		}
	}
	return empty
}

// ArrFindIndex 查找数组中满足条件的元素，找到时会提前结束，并返回该元素下标，否则返回-1
func ArrFindIndex[V any, T []V](arr T, fn func(val V, idx int) bool) int {
	for i, a := range arr {
		if fn(a, i) {
			return i
		}
	}
	return -1
}

// ArrFindLast 倒序查找数组中满足条件的元素，找到时会提前结束，并返回该元素
func ArrFindLast[V any, T []V](arr T, fn func(val V, idx int) bool) V {
	var empty V
	for i := len(arr) - 1; i >= 0; i-- {
		if fn(arr[i], i) {
			return arr[i]
		}
	}
	return empty
}

// ArrFindLastIndex 倒序查找数组中满足条件的元素，找到时会提前结束，并返回该元素下标，否则返回-1
func ArrFindLastIndex[V any, T []V](arr T, fn func(val V, idx int) bool) int {
	for i := len(arr) - 1; i >= 0; i-- {
		if fn(arr[i], i) {
			return i
		}
	}
	return -1
}

// ArrSome 判断数组中是否有一个元素满足条件，首次满足时结束
func ArrSome[V any, T []V](arr T, fn func(val V, idx int) bool) bool {
	for i, a := range arr {
		if fn(a, i) {
			return true
		}
	}
	return false
}

// ArrEvery 判断数组中是否所有元素都满足条件，首次不满足时结束
func ArrEvery[V any, T []V](arr T, fn func(val V, idx int) bool) bool {
	for i, a := range arr {
		if !fn(a, i) {
			return false
		}
	}
	return true
}

// ArrShift 从数组中移除并返回第一个元素
func ArrShift[V any, T []V](arr *T) V {
	var v V
	if l := len(*arr); l > 0 {
		v = (*arr)[0]
		*arr = (*arr)[1:]
	}
	return v
}

// ArrUnShift 添加一些元素到数组的开头，然后返回现有的元素个数
func ArrUnShift[V any, T []V](arr *T, vals ...V) int {
	*arr = ArrConcat(vals, *arr)
	return len(*arr)
}

// ArrPop 从数组中移除并返回最后一个元素
func ArrPop[V any, T []V](arr *T) V {
	var v V
	if l := len(*arr); l > 0 {
		v = (*arr)[l-1]
		*arr = (*arr)[:l-1]
	}
	return v
}

// ArrPush 添加一些元素到数组末尾，然后返回现有的元素个数
func ArrPush[V any, T []V](arr *T, vals ...V) int {
	*arr = ArrConcat(*arr, vals)
	return len(*arr)
}

// ArrSplice 从数组start位置开始，删去length个元素，并将val依次拼接至末尾，然后返回被删除的元素
//   - 若start为负数，则从末尾开始算，如：-5表示从倒数第5个元素开始
func ArrSplice[V any, T []V](arr *T, start, length int, val ...V) T {
	l := len(*arr)

	start = IIf(start < 0, max(l+start, 0), min(start, l))
	end := min(start+length, l)

	arr2 := make(T, end-start)
	if end > start {
		copy(arr2, (*arr)[start:end])
		*arr = append((*arr)[0:start], append((*arr)[end:], val...)...)
	} else {
		*arr = append(*arr, val...)
	}

	return arr2
}

// ArrJoin 将数组以指定分隔符拼接为字符串
func ArrJoin[V any, T []V, R any](arr T, sep R) string {
	return strings.Join(ArrMap(arr, func(v V, i int) string {
		return Str(v)
	}), Str(sep))
}

// Join 将数组以指定分隔符拼接为字符串
//   - ArrJoin的别名
func Join[V any, T []V, R any](arr T, sep R) string {
	return ArrJoin[V, T, R](arr, sep)
}
